package com.ssr.master.common.config;

import javax.servlet.Filter;

import com.ssr.master.common.filter.KickoutSessionControlFilter;
import com.ssr.master.common.shiro.RetryLimitCredentialsMatcher;
import com.ssr.master.common.shiro.ShiroRealm;
import com.ssr.master.modules.service.ShiroService;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.crazycake.shiro.RedisCacheManager;
import org.springframework.context.annotation.Configuration;


import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author ZhangPeng
 * @Describe //todo
 * @date
 * @updateBy
 * @other
 **/


@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager, ShiroService shiroService) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 没有登陆的用户只能访问登陆页面
        shiroFilterFactoryBean.setLoginUrl("/a/login");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/a/index");
        // 未授权界面; ----这个配置了没卵用，具体原因想深入了解的可以自行百度
        //shiroFilterFactoryBean.setUnauthorizedUrl("/auth/403");
        //自定义拦截器
        Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
        //限制同一帐号同时在线的个数。
        filtersMap.put("kickout", kickoutSessionControlFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);
        // 权限控制map
        Map<String, String> map = shiroService.loadFilterChainDefinitions();
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager(@Qualifier("shiroRealm") ShiroRealm authRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(authRealm);
        // 自定义缓存实现 使用redis
        securityManager.setCacheManager(cacheManager());
        // 自定义session管理 使用redis
        securityManager.setSessionManager(sessionManager());
        // 注入记住我管理器
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

   /**
    * @param
    * @return org.apache.shiro.web.mgt.CookieRememberMeManager
    * @Description //todo cookie管理对象;记住我功能
    * @author ZhangPeng
    * @date 2020/6/30 11:15
    * @other
   **/
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
        cookieRememberMeManager.setCipherKey(Base64.decode("1QWLxg+NYmxraMoxAXu/Iw=="));
        return cookieRememberMeManager;
    }

   /**
    * @param
    * @return org.apache.shiro.web.servlet.SimpleCookie
    * @Description //todo cookie对象;
    * @author ZhangPeng
    * @date 2020/6/30 11:15
    * @other
   **/
    public SimpleCookie rememberMeCookie() {
        // 这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        // 记住我cookie生效时间30天 ,单位秒。 注释掉，默认永久不过期 2018-07-15
        simpleCookie.setMaxAge(1800);
        return simpleCookie;
    }

    /**
     * @param
     * @return com.ssr.master.common.shiro.ShiroRealm
     * @Description //todo 身份认证realm; (这个需要自己写，账号密码校验；权限等)
     * @author ZhangPeng
     * @date 2020/6/20 16:05
     * @other
     **/
    @Bean
    public ShiroRealm shiroRealm(@Qualifier("credentialsMatcher") RetryLimitCredentialsMatcher matcher) {
        ShiroRealm shiroRealm = new ShiroRealm();
        shiroRealm.setCredentialsMatcher(credentialsMatcher());
        return shiroRealm;
    }

    /**
     * todo 凭证匹配器
     * （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     * 所以我们需要修改下doGetAuthenticationInfo中的代码;
     * ）
     *
     * @return
     */
    @Bean(name = "credentialsMatcher")
    public RetryLimitCredentialsMatcher credentialsMatcher() {
        return new RetryLimitCredentialsMatcher();
    }

    /**
     * @param
     * @return org.crazycake.shiro.RedisCacheManager
     * @Description //todo cacheManager 缓存 redis实现 使用的是shiro-redis开源插件
     * @author ZhangPeng
     * @date 2020/6/20 16:06
     * @other
     **/
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    /**
     * @param
     * @return org.crazycake.shiro.RedisManager
     * @Description //todo 配置shiro redisManager 使用的是shiro-redis开源插件
     * @author ZhangPeng
     * @date 2020/6/20 16:06
     * @other
     **/
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("localhost");
        redisManager.setPort(6379);
        redisManager.setExpire(1800);// 配置缓存过期时间
        redisManager.setTimeout(0);
        // redisManager.setPassword(password);
        return redisManager;
    }

    /**
     * @param
     * @return org.apache.shiro.web.session.mgt.DefaultWebSessionManager
     * @Description //todo Session Manager 使用的是shiro-redis开源插件
     * @author ZhangPeng
     * @date 2020/6/20 16:06
     * @other
     **/
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }


    /**
     * @param
     * @return org.crazycake.shiro.RedisSessionDAO
     * @Description //todo RedisSessionDAO shiro sessionDao层的实现 通过redis 使用的是shiro-redis开源插件
     * @author ZhangPeng
     * @date 2020/6/20 16:07
     * @other
     **/
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    /**
     * @param
     * @return KickoutSessionControlFilter
     * @Description //todo 限制同一账号登录同时登录人数控制
     * @author ZhangPeng
     * @date 2020/6/20 16:07
     * @other
     **/
    @Bean
    public KickoutSessionControlFilter kickoutSessionControlFilter() {
        KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter();
        kickoutSessionControlFilter.setCacheManager(cacheManager());
        kickoutSessionControlFilter.setSessionManager(sessionManager());
        kickoutSessionControlFilter.setKickoutAfter(false);
        kickoutSessionControlFilter.setMaxSession(1);
        kickoutSessionControlFilter.setKickoutUrl("/a/login");
        return kickoutSessionControlFilter;
    }

    /**
     * @param
     * @return org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
     * @Description //todo 授权所用配置
     * @author ZhangPeng
     * @date 2020/6/20 16:07
     * @other
     **/
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * @param securityManager
     * @return org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor
     * @Description //todo 使授权注解起作用不如不想配置可以在pom文件中加入
     * <dependency>
     * <groupId>org.springframework.boot</groupId>
     * <artifactId>spring-boot-starter-aop</artifactId>
     * </dependency>
     * @author ZhangPeng
     * @date 2020/6/20 16:07
     * @other
     **/
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * @param
     * @return org.apache.shiro.spring.LifecycleBeanPostProcessor
     * @Description //todo Shiro生命周期处理器
     * @author ZhangPeng
     * @date 2020/6/20 16:08
     * @other
     **/
    @Bean
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }


}
